/* globals seConfirm */
/**
 * @file ext-primitives.js
 *
 * @license MIT
 *
 * @copyright 2020 OptimistikSAS
 *
 */

/**
   * @type {module:svgcanvas.EventHandler}
   * @param {external:Window} wind
   * @param {module:svgcanvas.SvgCanvas#event:saved} svg The SVG source
   * @listens module:svgcanvas.SvgCanvas#event:saved
   * @returns {void}
   */
import { fileOpen } from 'browser-fs-access'

const name = 'server-opensave'
let handle = null

const loadExtensionTranslation = async function (svgEditor) {
  let translationModule
  const lang = svgEditor.configObj.pref('lang')
  try {
    translationModule = await import(`./locale/${lang}.js`)
  } catch (_error) {
    console.warn(`Missing translation (${lang}) for ${name} - using 'en'`)
    translationModule = await import('./locale/en.js')
  }
  svgEditor.i18next.addResourceBundle(lang, 'translation', translationModule.default, true, true)
}

export default {
  name,
  async init(_S) {
    const svgEditor = this
    const { svgCanvas, storage } = svgEditor
    const { $id, $click, $qq } = svgCanvas
    var state = null;
    var undoSize = 0
    var initSize = 0;
    var switchClick = false
    var updateDocData = false
    await loadExtensionTranslation(svgEditor)
    /**
    * @param {Event} e
    * @returns {void}
    */
    const importImage = (e) => {
      $id('se-prompt-dialog').title = this.i18next.t('notification.loadingImage')
      $id('se-prompt-dialog').setAttribute('close', false)
      e.stopPropagation()
      e.preventDefault()
      const file = (e.type === 'drop') ? e.dataTransfer.files[0] : e.currentTarget.files[0]
      if (!file) {
        $id('se-prompt-dialog').setAttribute('close', true)
        return
      }

      if (!file.type.includes('image')) {
        return
      }
      // Detected an image
      // svg handling
      let reader
      if (file.type.includes('svg')) {
        reader = new FileReader()
        reader.onloadend = (ev) => {
          const newElement = svgCanvas.importSvgString(ev.target.result, true)
          svgCanvas.alignSelectedElements('m', 'page')
          svgCanvas.alignSelectedElements('c', 'page')
          // highlight imported element, otherwise we get strange empty selectbox
          svgCanvas.selectOnly([newElement])
          $id('se-prompt-dialog').setAttribute('close', true)
        }
        reader.readAsText(file)
      } else {
        // bitmap handling
        reader = new FileReader()
        reader.onloadend = function ({ target: { result } }) {
          /**
              * Insert the new image until we know its dimensions.
              * @param {Float} imageWidth
              * @param {Float} imageHeight
              * @returns {void}
              */
          const insertNewImage = (imageWidth, imageHeight) => {
            const newImage = svgCanvas.addSVGElementsFromJson({
              element: 'image',
              attr: {
                x: 0,
                y: 0,
                width: imageWidth,
                height: imageHeight,
                id: svgCanvas.getNextId(),
                style: 'pointer-events:inherit'
              }
            })
            svgCanvas.setHref(newImage, result)
            svgCanvas.selectOnly([newImage])
            svgCanvas.alignSelectedElements('m', 'page')
            svgCanvas.alignSelectedElements('c', 'page')
            svgEditor.topPanel.updateContextPanel()
            $id('se-prompt-dialog').setAttribute('close', true)
          }
          // create dummy img so we know the default dimensions
          let imgWidth = 100
          let imgHeight = 100
          const img = new Image()
          img.style.opacity = 0
          img.addEventListener('load', () => {
            imgWidth = img.offsetWidth || img.naturalWidth || img.width
            imgHeight = img.offsetHeight || img.naturalHeight || img.height
            insertNewImage(imgWidth, imgHeight)
          })
          img.src = result
        }
        reader.readAsDataURL(file)
      }
    }
    // create an input with type file to open the filesystem dialog
    const imgImport = document.createElement('input')
    imgImport.type = 'file'
    imgImport.addEventListener('change', importImage)
    // dropping a svg file will import it in the svg as well
    this.workarea.addEventListener('drop', importImage)
    /**
     * @fires module:svgcanvas.SvgCanvas#event:ext_onNewDocument
     * @returns {void}
     */
    const clickClear = async function () {
      var ishasElement = hasOpration();
      if (window.urlType == 'ElementEditing') {
        state = null;
        storage.setItem('svg-edit-primitiveDesc', '')
        storage.setItem('svg-edit-primitiveType', '')
        if (ishasElement && hasElement()) {
          showSave()
        } else {
          showSetElement()
          saveAfterClear()

        }

      } else {
        if (ishasElement && hasElement()) {
          showSave();
        } else {
          saveAfterClear()
        }
      }
    }

    const ElementProperties = function () {
      state = null;
      if (svgEditor.newElement) {
        return
      }
      svgEditor.newElement = true
      if (!storage.getItem('svg-edit-primitiveDesc')) {
        storage.setItem('svg-edit-primitiveDesc', '开关')
      }

      if (!storage.getItem('svg-edit-primitiveType')) {
        storage.setItem('svg-edit-primitiveType', '开关')
      }
      const $imgDialog = $id('se-element')
      $imgDialog.setAttribute('title-text', '图元属性设置')
      $imgDialog.setAttribute('primitives-desc', storage.getItem('svg-edit-primitiveDesc'))
      $imgDialog.setAttribute('primitives-type', storage.getItem('svg-edit-primitiveType'))
      $imgDialog.setAttribute('dialog', 'open')
      $imgDialog.setAttribute('common-cancel-hide', false)
    }
    /**
     * By default,  this.editor.svgCanvas.open() is a no-op. It is up to an extension
     *  mechanism (opera widget, etc.) to call `setCustomHandlers()` which
     *  will make it do something.
     * @returns {void}
     */
    const clickOpen = async function () {
      // ask user before clearing an unsaved SVG
      var ishasElement = hasOpration();
      if (ishasElement) {
        const response = await svgEditor.openPrep()
        if (response === 'Cancel') { openCall(); return false; }
        clickSave(openCall);
      } else {
        openCall();
      }
    }

    const openCall = async function () {
      try {
        const blob = await fileOpen({
          mimeTypes: ['image/svg+xml']
        })
        const svgContent = await blob.text()
        await svgEditor.loadSvgString(svgContent)
        svgEditor.updateCanvas()
        handle = blob.handle
        svgEditor.layersPanel.populateLayers()
        svgEditor.topPanel.updateTitle(blob.name)
        // var bgColor = svgEditor.configObj.pref('bkgd_color')
        // svgEditor.setBackground(bgColor,null)
        svgEditor.svgCanvas.runExtensions('onOpenedDocument', {
          name: blob.name,
          lastModified: blob.lastModified,
          size: blob.size,
          type: blob.type
        })
      } catch (err) {
        if (err.name !== 'AbortError') {
          return console.error(err)
        }
      }
    }

    const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
      const byteCharacters = atob(b64Data)
      const byteArrays = []
      for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize)
        const byteNumbers = new Array(slice.length)
        for (let i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i)
        }
        const byteArray = new Uint8Array(byteNumbers)
        byteArrays.push(byteArray)
      }
      const blob = new Blob(byteArrays, { type: contentType })
      return blob
    }
    const hasElement = function () {
      var drawing = svgEditor.svgCanvas.getCurrentDrawing();
      var allLays = drawing.all_layers
      var ishasElement = false;
      for (var i = 0; i < allLays.length; i++) {
        var currentLayer = drawing.all_layers[i]
        const children = currentLayer.getChildren()
        if (children.length > 1) {
          ishasElement = true;
          break;
        }
      }
      return ishasElement;
    }

    /**
     * 工具栏保存方法
     * @returns {void}
     */
    const clickSave = async function (fn) {
      var ishasElement = hasElement();
      if (ishasElement) {
        let { x, y, width, height } = svgCanvas.getSvgContent().getBBox()
        let svgContent = svgCanvas.getSvgContent().cloneNode(true)
        svgContent.setAttribute('width', width)
        svgContent.setAttribute('height', height)
        svgContent.removeAttribute('x')
        svgContent.removeAttribute('y')
        svgContent.setAttribute('viewBox', `${x} ${y} ${width} ${height}`)

        const svg = svgContent.outerHTML
        const b64Data = svgCanvas.encode64(svg)
        const blob = b64toBlob(b64Data, 'image/svg+xml')
        if (!storage.getItem('svg-edit-primitiveType')) {
          storage.setItem('svg-edit-primitiveType', '开关')
        }
        if (!storage.getItem('svg-edit-primitiveDesc')) {
          storage.setItem('svg-edit-primitiveDesc', '开关')
        }
        const primitiveType = storage.getItem('svg-edit-primitiveType');
        const primitiveDesc = storage.getItem('svg-edit-primitiveDesc');

        var responseView = await fetch(`${svgEditor.configObj.curConfig.serviceUrl}/svg/primitive/list`)
        var Viewdata = (await responseView.json()).data;
        var sameName = false;

        Object.entries(Viewdata).forEach(([key, value]) => {
          if (key == primitiveType) {
            value.forEach((gs) => {
              let title = gs.title;
              if (title === primitiveDesc) {
                sameName = true;
              }
            })
          }
        })

        if (sameName) {
          //存在相同名
          const ok = await seConfirm(svgEditor.i18next.t('notification.has_same_name'))
          if (ok == 'Ok') {
            const data = new FormData();
            data.append('file', blob);
            data.append('type', primitiveType);
            data.append('name', primitiveDesc);

            const response = await fetch(`${svgEditor.configObj.curConfig.serviceUrl}/svg/primitive`, {
              method: 'POST',
              body: data
            });

            const success = `${name}.notification.ok`
            const fail = `${name}.notification.fail`
            const json = await response.json()
            const message = svgEditor.i18next.t(json.code === '100000' ? success : fail)
            var choice = await seAlert(message)
            if (choice == 'Ok') {
              if (typeof fn == 'function') {
                svgEditor.svgCanvas.clear()
                fn();
              }
            }

          } else {
            //存在相同名时候取消操作不做保存  有回调函数执行回调
            if (typeof fn == 'function') {
              fn();
            }
          }

        } else {
          const data = new FormData();
          data.append('file', blob);
          data.append('type', primitiveType);
          data.append('name', primitiveDesc);

          const response = await fetch(`${svgEditor.configObj.curConfig.serviceUrl}/svg/primitive`, {
            method: 'POST',
            body: data
          });
          const success = `${name}.notification.ok`
          const fail = `${name}.notification.fail`
          const json = await response.json()
          const message = svgEditor.i18next.t(json.code === '100000' ? success : fail)
          var choice = await seAlert(message)
          if (choice) {
            if (typeof fn == 'function') {
              svgEditor.svgCanvas.clear()
              fn();
            }
          }
        }

      } else {
        if (typeof fn == 'function') {
          //打开svg  不存在保存元素直接打开文件
          svgEditor.svgCanvas.clear()
          fn();
        } else {
          await seAlert(svgEditor.i18next.t('notification.not_has_elem'))
        }

      }
    }

    const saveNewElementInfo = function (e) {
      const {
        PrimitivesType,
        PrimitivesDesc
      } = e.detail;
      storage.setItem('svg-edit-primitiveDesc', PrimitivesDesc)
      storage.setItem('svg-edit-primitiveType', PrimitivesType)
      svgEditor.updateCanvas(true)
      cancelNewElementInfo()
      if (state == 'newSave') {
        clickSave()
      }
      if (state) {
        saveAfterClear();
      }
    }

    const cancelNewElementInfo = function (type) {
      if (type == 'views') {
        const $editDialog = $id('se-view')
        $editDialog.setAttribute('dialog', 'close')
      } else {
        const $editDialog = $id('se-element')
        $editDialog.setAttribute('dialog', 'close')
        svgEditor.configObj.newElement = false
      }
    }

    const saveAfterClear = function () {
      const [x, y] = svgEditor.configObj.curConfig.dimensions
      svgEditor.leftPanel.clickSelect()
      svgEditor.svgCanvas.clear()
      svgEditor.svgCanvas.setResolution(x, y)
      svgEditor.updateCanvas(true)
      svgEditor.zoomImage()
      svgEditor.layersPanel.populateLayers()
      svgEditor.topPanel.updateContextPanel()
      svgEditor.topPanel.updateTitle('untitled.svg')
      svgEditor.svgCanvas.runExtensions('onNewDocument')
      initSize = undoSize = 0
      updateDocData = false
      // var bgColor = svgEditor.configObj.pref('bkgd_color')
      // svgEditor.setBackground(bgColor,null)
    }
    /**
     * 图元预览
     * @param e pointEvent 鼠标点击事件参数
     * @constructor
     */

    const ViewPrimite = function (e) {
      const $imgDialog = $id('se-view')
      $imgDialog.setAttribute('dialog', 'open')
      // $imgDialog.setAttribute('time-change', new Date())

    }

    //展示新建图元属性框
    const showSetElement = function (e) {
      const $imgDialog = $id('se-element')
      $imgDialog.setAttribute('dialog', 'open')

    }


    const showSave = function () {
      const $save = $id('se-save')
      $save.setAttribute('dialog', 'open')
    }


    const hideSave = function () {
      const $save = $id('se-save')
      $save.setAttribute('dialog', 'close')
    }

    //新建 保存后操作
    const newSave = function () {
      //图元编辑逻辑
      if (window.urlType == 'ElementEditing') {
        state = 'newSave'
        hideSave()
        showSetElement()
      } else {
        //图形编辑逻辑 这边图形编辑 保存暂时不做处理 简单清空
        state = 'newSave'
        hideSave()
        // saveAfterClear()
        $("#se-grahicsave").attr('dialog', 'open')
        const primitiveType = storage.getItem('svg-edit-graphicType');
        const primitiveDesc = storage.getItem('svg-edit-graphicDesc');
        if(primitiveType){
          $("#se-grahicsave").attr('graphic-type', primitiveType)
        }
        if(primitiveDesc){
          $("#se-grahicsave").attr('graphic-desc',primitiveDesc)
        }
      }
    }

    //新建  不保存关闭后操作
    const donSaveClose = function () {
      //图元编辑逻辑
      if (window.urlType == 'ElementEditing') {
        state = 'donotSaveClose'
        hideSave()
        showSetElement()
      } else {
        if(switchClick == true){
          switchClick = false
          window.open("./svg.html","_self")
          return
        }
        state = 'donotSaveClose'
        hideSave()
        saveAfterClear()
      }
    }

    //这边是图像预览处理
    const seeGraphic = function () {
      if(hasOpration() && hasElement()){
        showSave()
      }else{
        const $save = $id('se-viewgrahic')
        $save.setAttribute('dialog', 'open')
      }
    }


    const SaveGraphic = async function () {
      if(window.urlType == 'ElementEditing'){
        clickSave()
        return
      }
      var ishasElement = hasElement();
      if (ishasElement) {
        $("#se-grahicsave").attr('dialog', 'open')
        const primitiveType = storage.getItem('svg-edit-graphicType');
        const primitiveDesc = svgEditor.descTitle
        if(primitiveType){
          $("#se-grahicsave").attr('graphic-type', primitiveType)
        }

        if(primitiveDesc){
          $("#se-grahicsave").attr('graphic-desc',primitiveDesc)
        }

      } else {
        await seAlert(svgEditor.i18next.t('notification.not_has_elem'))
      }
    }

    const hasOpration = function () {
      if(undoSize !=initSize){
        return true
      }
      if(updateDocData){
        return true
      }
      return false
    }

    const reloadPrim = function(){
      svgEditor.svgCanvas.runExtensions("reloadSymbol")
    }

    const switchSystem = async function () {
      window.parent.showLeftPanel = true
      var ishasOpt = hasOpration();
      //操作变化 且需要加上是否有相应元素
      if (ishasOpt && hasElement()) {
        showSave();
        switchClick = true
      }else{
        const event=new CustomEvent('ToShow');
        window.parent.dispatchEvent(event)
        window.open("./svg.html","_self")
      }
    }


    //保存预览
    const SaveGraphicdone = async function () {
      const primitiveType = storage.getItem('svg-edit-graphicType');
      const primitiveDesc = storage.getItem('svg-edit-graphicDesc');
      var responseView = await fetch(`${svgEditor.configObj.curConfig.serviceUrl}/svg/graphics/list`)
      var Viewdata = (await responseView.json()).data;
      var sameName = false;

      Object.entries(Viewdata).forEach(([key, value]) => {
        if (key == primitiveType) {
          value.forEach((gs) => {
            let title = gs.title;
            if (title === primitiveDesc) {
              sameName = true;
            }
          })
        }
      })

      if (sameName) {
        const ok = await seConfirm(svgEditor.i18next.t('notification.has_same_name'))
        if (ok == 'Ok') {
          GraphicesaveRequest()
        }
      } else {
        GraphicesaveRequest()
      }

      async function GraphicesaveRequest() {
        let { x, y, width, height } = svgCanvas.getSvgContent().getBBox()
        let svgContent = svgCanvas.getSvgContent().cloneNode(true)
        svgContent.setAttribute('width', width)
        svgContent.setAttribute('height', height)
        svgContent.removeAttribute('x')
        svgContent.removeAttribute('y')
        svgContent.setAttribute('viewBox', `${x} ${y} ${width} ${height}`)

        // var bgurl = localStorage.getItem("svg-edit-bkgd_url")
        
        // var bgcolor = localStorage.getItem('svg-edit-bkgd_color')
        // if(bgurl && bgurl!=null&& bgurl!="null"){
        //   svgContent.setAttribute("bgurl",bgurl)
        //   svgContent.setAttribute('bgcolor','')
        // }else{
        //   svgContent.setAttribute('bgcolor',bgcolor)
        //   svgContent.setAttribute("bgurl",'')
        // }
        const svg = svgContent.outerHTML
        const b64Data = svgCanvas.encode64(svg)
        const blob = b64toBlob(b64Data, 'image/svg+xml')
        //TODO
        const data = new FormData();
        data.append('file', blob);
        data.append('type', primitiveType);
        data.append('name', primitiveDesc);
        const response = await fetch(`${svgEditor.configObj.curConfig.serviceUrl}/svg/graphics`, {
          method: 'POST',
          body: data
        });
        const success = `${name}.notification.ok`
        const fail = `${name}.notification.fail`
        const json = await response.json()
        const message = svgEditor.i18next.t(json.code === '100000' ? success : fail)
        var choice = await seAlert(message)
        initSize = undoSize
        updateDocData = false
        // if(switchClick == true){
        //   switchClick = false
        //   window.open("./svg.html","_self")
        // }
      }
    }

    return {
      name: svgEditor.i18next.t(`${name}:name`),
      SaveGraphic:SaveGraphic,
      sourceChanged(opts){
        initSize = undoSize
        updateDocData = false
      },
      elementChanged(opts) {
        undoSize = svgEditor.svgCanvas.undoMgr.undoStack.length
      },
      updateProp(){
        updateDocData = true
      },
      Replacement(res){
        if(res.data && res.data.length){

          for(let i=0;i<res.data.length;i++){
             let {svg_id,afterData,chooseNameLable,equipmentLable} = res.data[i];
             if(afterData){
               $(`#${svg_id}`).attr('data',afterData);
             }
            
             if($(`#${svg_id}`).attr('state')){
              var enCode =  $(`#${svg_id}`).attr('state');
              var deCode = JSON.parse(decodeURIComponent(escape(atob(enCode))));
              if(chooseNameLable){
                deCode.chooseNameLable =chooseNameLable;
              }

              if(equipmentLable){
                deCode.equipmentLable=equipmentLable;
              }
              
            
              $(`#${svg_id}`).attr("state", btoa(unescape(encodeURIComponent(JSON.stringify(deCode)))))

             }else{
               continue;
             }
           

             
          }

        }
     },
      hasOpration:hasOpration,
      // The callback should be used to load the DOM with the appropriate UI items
      callback() {
        const buttonTemplate = `
        <se-button id="tool_clear" title="server-opensave.new_doc"  src="new.svg"></se-button>`
        svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), buttonTemplate, 0)
        const openButtonTemplate = '<se-button id="tool_open" title="server-opensave.open_image_doc" src="open.svg"></se-button>'
        svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), openButtonTemplate, 1)

        if (window.urlType === 'ElementEditing') {
          // 工具栏按钮组
          const saveButtonTemplate = `<se-button id="tool_save_primitive" title="server-opensave.save_doc"  src="saveImg.svg"></se-button>`
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), saveButtonTemplate, 2)
          const attarTemplate = `
          <se-button id="Element_properties" title="server-opensave.attr"  src="docprop.svg"></se-button>`
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), attarTemplate, -1)
          const ViewPrimiteTemplate = '<se-button id="ViewPrimite" title="tools.primiteView"  src="viewpel.svg"></se-button>'
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), ViewPrimiteTemplate, -1)
          const importButtonTemplate = '<se-button id="tool_import" title="tools.import_doc" src="importImg.svg"></se-menu-item>'
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), importButtonTemplate, 3)
          $click($id('Element_properties'), ElementProperties.bind(this))
          $click($id('ViewPrimite'), ViewPrimite.bind(this))
          $click($id('tool_import'), () => imgImport.click())
          $click($id('tool_save_primitive'), clickSave.bind(this))
        } else {
          const switchButtonTemplate = `<se-button id="tool_switch" title="svg.switchSvg"  src="source.svg"></se-button>`
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), switchButtonTemplate, 0)

          const ViewEditorTemplate = '<se-button id="ViewEditorGraphic" title="tools.GraphicView"  src="viewpel.svg"></se-button>'
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), ViewEditorTemplate, -1)

          const saveButtonGraphic = `<se-button id="tool_save_graphic" title="server-opensave.save_doc"  src="saveImg.svg"></se-button>`
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), saveButtonGraphic, 2)

          const reloadButton = `<se-button id="tool_reload" title="svg.reloadpic" src="reload.svg" ></se-button>`
          svgCanvas.insertChildAtIndex($qq('.toolbarWrap .itemWrap'), reloadButton, 4)
          $click($id('ViewEditorGraphic'), seeGraphic.bind(this))
          $click($id('tool_save_graphic'), SaveGraphic.bind(this))
          $click($id('tool_switch'), switchSystem.bind(this))
          $click($id('tool_reload'), reloadPrim.bind(this))
        }


        $click($id('tool_clear'), clickClear.bind(this))
        $click($id('tool_open'), clickOpen.bind(this))

        $id('se-grahicsave').addEventListener(
          'change',
          function (e) {
            if (e.detail.dialog === 'closed') {
              $("#se-grahicsave").attr('dialog', 'close')
            } else {
              svgEditor.storage.setItem('svg-edit-graphicType',e.detail.graphicType)
              svgEditor.storage.setItem('svg-edit-graphicDesc', e.detail.graphicDesc)
              SaveGraphicdone()
              $("#se-grahicsave").attr('dialog', 'close')
            }
          }.bind(this)
        )

        $id('se-element').addEventListener(
          'change',
          function (e) {
            if (e.detail.dialog === 'closed') {
              cancelNewElementInfo(e)
            } else {
              saveNewElementInfo(e)
            }
          }.bind(this)
        )

        $id('se-view').addEventListener(
          'change',
          function (e) {
            if (e.detail.dialog === 'closed') {
              cancelNewElementInfo('views')
            } else {
              // saveNewElementInfo(e)
            }
          }.bind(this)
        )

        $id('se-viewgrahic').addEventListener(
          'change',
          function (e) {
            if (e.detail.dialog === 'closed') {
              $('#se-viewgrahic').attr('dialog','close')

            } else {
              $('#se-viewgrahic').attr('dialog','close')
              // saveNewElementInfo(e)
            }
          }.bind(this)
        )

        $id('se-save').addEventListener(
          'change',
          function (e) {
            if (e.detail.dialog === 'closed') {
              hideSave()
            } else if (e.detail.dialog == 'saves') {
              newSave()
            } else {
              donSaveClose()

            }
          }.bind(this)
        )

      }
    }
  }
}
